//== SAGITTARIUS ============================================================================

//== BEGINNING OF CODE ===============================================================

#include "sagittarius/core/SagittariusCore.h"
#include "sagittarius/mem/pageheap.h"
#include "sagittarius/parallel/multisema.h"
#include "sagittarius/io/io.h"

//#define __USE_GNU
//#include <linux/futex.h>
//#include <sys/time.h>
//#include <sys/syscall.h>
//#include <limits.h>



#define HEAP_SEMA_INIT      INITSEMA(smoheap->sema)
#define HEAP_WRITER         WLSEMA(smoheap->sema)
#define HEAP_WRITER_DONE    WUSEMA(smoheap->sema)
#define HEAP_READER         RLSEMA(smoheap->sema)
#define HEAP_READER_DONE    RUSEMA(smoheap->sema)

#define BASE_SPAN_PGS   4

int init_smo_heap(sg_smoheap* smoheap, spanhash_t** sh) {
    int i;
    //void* obj;
    sg_pageheap* ph;
    void *base, *sp;
    
    HEAP_SEMA_INIT;
    
    HEAP_WRITER;
    
    //create hash table for page addresses
    AZ(*sh);
    *sh = ht64_rehash(NULL, 2*SG_NUM_SIZECLASSES, 4);
    
    //allocate initial memory for the heap
    base = sg_sysalloc(BASE_SPAN_PGS*SG_NUM_SIZECLASSES);
    
    for(i = 1; i<=SG_NUM_SIZECLASSES; ++i) {
        ph = &smoheap->heaps[i-1];
        ph->gf = 1;
        ph->spans[0].sc = (sg_sclass)i;
        sp = (uint8*)base + BASE_SPAN_PGS*SG_PAGE_SIZE*(i-1);
        //DONE: one big alloc
        if(init_span(&ph->spans[0], sp, BASE_SPAN_PGS*ph->gf, sg_sc_nbytes(i) <= 8)) {
            AN(0);
            return 1;
        }
        //add span to map
        /*SG_WRITE(2, "adding span to hash: ");
        sg_writePtr(2, sp);
        SG_WRITE(2, "\n");*/
        AT( ht64_insert(*sh, (void*)&sp, SG_PTR_SIZE, SG_PTR_SIZE) == HASH_SUCCESS );
    }
    
    HEAP_WRITER_DONE;
    
    return 0;
}

int destroy_smo_heap(sg_smoheap* smoheap) {
    //TODO: manage smo heap in large list
    return 0;
}

//small objects
void* smo_heapalloc(sg_smoheap* smoheap, sg_sclass b) {
    void* r;
    sg_pageheap* ph;
    AT(1 <= b && b <= SG_NUM_SIZECLASSES);
    
    HEAP_READER; //only need to lock HEAP_WRITER when chainging the heap itself, not when making changes within a span
    
    ph = &smoheap->heaps[b-1];
    r = smo_allocs_b(&ph->spans[0]); //FIXME: pegged to span 0
    AN(r, "Small object allocation failed");
    
    HEAP_READER_DONE;
    
    return r;
}